package daytrader.gui;

import java.util.*;

import java.awt.*;

import javax.swing.JPanel;

import daytrader.data.TickData;
import daytrader.lib.LibData;
import daytrader.lib.LibDataInterface;
import daytrader.framework.Engine;
import daytrader.framework.Tick;
import daytrader.types.Portfolio;
import daytrader.types.Hold;
import daytrader.types.Stock;

public class GUI extends JPanel 
{
    // drawing parameters
    public static final int PADDING = 20;
    public static final int GRID = 10;
    public static final int TICKS = 50;
    
    public static final double CANDLE_WIDTH = 0.8;
    public static final int DATA_PADDING = 50;
    
    public static final int PORTFOLIO_HEIGHT = 200;
    
    public String stockName = "GOOG";
    
    // references to data source
    public Engine engine;
    public LibData libData;

    // real time control
    private int lastTick = 0;
    
    // temporaries for drawing
    private int w;
    private int h;
    private int ew;
    private int eh;
    private double min;
    private double max;
    private double sy;
    private Graphics2D g2;
    
    // tracking of the portfolio history
    //private ArrayList<Portfolio> portfolioHistory;
    private PortfolioGraph pg;
    private ArrayList<ArrayList<StockHistoryData>> stockHistory;
    
    public GUI(Engine e)
    {
        engine = e;
        libData = (LibData)engine.getLibData();
        
        //portfolioHistory = new ArrayList<Portfolio>();
        stockHistory = new ArrayList<ArrayList<StockHistoryData>>();
        
        pg = new PortfolioGraph(this);
        this.add(pg);
    }
    
    public void setObservingStockName(String observingStockName)
    {
        this.stockName = observingStockName;
    }
    
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g2 = (Graphics2D)g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
       
        w = getWidth();
        h = getHeight() - PORTFOLIO_HEIGHT;
        ew = w - 2 * PADDING;
        eh = h - 2 * PADDING;

        sy = (eh - 2 * DATA_PADDING) / (max - min);

        pg.setSize(w, PORTFOLIO_HEIGHT);
        pg.setLocation(0, h);
        
        // read data
        //libData.openStockFeed(stockName);
        LibData.TickRange tr = libData.getTicks(TICKS, stockName);
        
        /*if (portfolioHistory.size() == TICKS)
            portfolioHistory.remove(0);
        //portfolioHistory.add(engine.getPortfolio());
        Portfolio pclone = new Portfolio();
        pclone.stocks = new ArrayList<Hold>();
        for (int i = 0; i < engine.getPortfolio().stocks.size(); i++)
        {
            Hold h = engine.getPortfolio().stocks.get(i);
            Hold hclone = new Hold(h.stock, h.amount, h.price);
            pclone.stocks.add(hclone);
        }
        portfolioHistory.add(pclone);
        */
        
        if (stockHistory.size() == TICKS)
            stockHistory.remove(0);
        ArrayList<StockHistoryData> stocks = new ArrayList<StockHistoryData>();
        for (int i = 0; i < libData.listStockNames().length; i++)
        {
            String name = libData.listStockNames()[i];
            //System.out.println(name);
            //libData.openStockFeed(name);
            StockHistoryData s = new StockHistoryData();
            s.name = name;
            s.price = libData.close(0, stockName);
            s.amount = 0;
            s.bought_price = 0;
            s.accumulative_profit = 0;
            
            // set profit to equal to the last record
            StockHistoryData lasthold = null;
            if (stockHistory.size() > 0)
            {
                for (int j = 0; j < libData.listStockNames().length; j++)
                {
                    if (stockHistory.get(stockHistory.size() - 1).get(j).name.equals(s.name))
                    {
                        lasthold = stockHistory.get(stockHistory.size() - 1).get(j);
                    }
                }
            }
            if (lasthold != null)
                s.accumulative_profit = lasthold.accumulative_profit;
            
            // update using current hold
            Hold currenthold = null;
            for (int j = 0; j < engine.getPortfolio().stocks.size(); j++)
            {
                Hold h = engine.getPortfolio().stocks.get(j);
                if (h.stock.company_name().equals(s.name))
                {
                    currenthold = h;
                    break;
                }
            }
            if (currenthold != null)
            {
                s.amount = currenthold.amount;
                s.bought_price = currenthold.price;
                if (lasthold != null && s.amount < lasthold.amount)
                    s.accumulative_profit += (lasthold.amount - s.amount) * (s.price - s.bought_price);
            }            
            
            stocks.add(s);
        }
        stockHistory.add(stocks);
        
        // find data bounds
        max = Double.MIN_VALUE;
        min = Double.MAX_VALUE;
        for (int i = 0; i < TICKS; i++)
        {
            TickData t = tr.tick(i);
            if (t.high > max) max = t.high;
            if (t.low < min) min = t.low;
        }
        
        // draw axis
        //g2.draw(new Line2D.Double(PADDING, PADDING, PADDING, h - PADDING));
        //g2.draw(new Line2D.Double(PADDING, h - PADDING, w - PADDING, h - PADDING));
        g2.drawLine(PADDING, PADDING, PADDING, h - PADDING);            // vertical
        g2.drawLine(PADDING, h - PADDING, w - PADDING, h - PADDING);    // horizontal
        
        // draw grid
        drawGrid();
    
        // draw candles
        drawCandles(tr);
        
        // draw stock name
        g2.setColor(Color.BLACK);
        g2.drawString(stockName, PADDING, PADDING - 10);
        
        // sleep until the next tick, and repaint
        //this.lastTick = Tick.waitNextTick(this.lastTick);
        //repaint(0, 0, 0, w, h);
        pg.repaint(0, 0, w, PORTFOLIO_HEIGHT);
        //System.exit(0);
    }
    
    protected void drawGrid()
    {
        /*
        for (int i = 0; i <= GRID; i++)
        {
            g2.drawLine(PADDING + i * ew / GRID, PADDING, PADDING + i * ew / GRID, h - PADDING);        // vertical 
            g2.drawLine(PADDING, PADDING + i * eh / GRID, w - PADDING, PADDING + i * eh / GRID);        // horizontal
        }
        */

        double logspan = Math.log10(max - min);
        double diff = logspan - Math.floor(logspan - 0.5);
        int flogspan = (int)Math.floor(logspan - 0.5);
        double tick = 1.0;
        if (flogspan > 0)   for (int i = 0; i < flogspan; i++) tick *= 10;
        else                for (int i = 0; i > flogspan; i--) tick /= 10;
            
        if (diff > 1.0)
            tick *= 2;
        else if (diff <= 0.7)
            tick /= 2;
        
        //System.out.println("logspan = " + logspan + " diff = " + diff + " tick = " + tick);
        
        double gmin = min - DATA_PADDING / sy;
        double gmax = max + DATA_PADDING / sy;
        g2.setFont(new Font("Helvetica", Font.PLAIN, 8));
        //System.out.println("sy = " + sy + " gmin = " + gmin + " gmax = " + gmax);
        for (double line = (gmin - (gmin % tick)); line <= gmax; line += tick)
        {
            int y = (int)(h - PADDING - DATA_PADDING - (line - min) * sy);
            //System.out.println("line = " + (float)line + " y = " + y);
            if (y >= PADDING && y <= h - PADDING)
            {
                g2.setColor(Color.LIGHT_GRAY);
                g2.drawLine(PADDING, y, w - PADDING, y);
                g2.setColor(Color.BLACK);
                g2.drawString(Float.valueOf((float)line).toString(), PADDING - 18, y + 4);
            }
        }
    }
    
    protected void drawCandles(LibData.TickRange tr)
    {
        int cw = (int)(ew * CANDLE_WIDTH / TICKS);
        for (int i = 0; i < TICKS; i++)
        {
            TickData t = tr.tick(i);
            //System.out.println("tick " + i + ": " + t.open + ", " + t.close + ", " + t.high + ", " + t.low);
            int x = (int)(PADDING + (i + 0.5) * ew / TICKS);
            int yopen   = (int)(h - PADDING - DATA_PADDING - (t.open - min) * sy);
            int yclose  = (int)(h - PADDING - DATA_PADDING - (t.close - min) * sy);
            int yhigh   = (int)(h - PADDING - DATA_PADDING - (t.high - min) * sy);
            int ylow    = (int)(h - PADDING - DATA_PADDING - (t.low - min) * sy);
            
            if (t.close > t.open)
                g2.setColor(Color.GREEN);
            else 
                g2.setColor(Color.RED);
            g2.drawLine(x, yhigh, x, ylow);
            g2.fillRect(x - cw / 2, Math.min(yopen, yclose), cw, Math.abs(yclose - yopen));
        }
        int i = TICKS - 1;
        TickData t = tr.tick(i);
        //System.out.println("tick " + i + ": " + t.open + ", " + t.close + ", " + t.high + ", " + t.low);
    }
    
    public ArrayList<ArrayList<StockHistoryData>> getStockHistory()
    {
        return stockHistory;
    }
    
}
